package com.mishow.widget;

import com.mishow.R;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;

/**
 * 
 * 作者：wei.miao <br/>
 * 描述：
 */
public class CircularImageView extends ImageView {
    // 边界和选择器配置变量
    private boolean hasBorder;
    private boolean hasSelector;
    private boolean isSelected;
    private int borderWidth;
    private int canvasSize;
    private int selectorStrokeWidth;

    // 对象用于实际的绘图
    private BitmapShader shader;
    private Bitmap image;
    private Paint paint;
    private Paint paintBorder;
    private Paint paintSelectorBorder;
    private ColorFilter selectorFilter;

    public CircularImageView(Context context) {
        this(context, null);
    }

    public CircularImageView(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.circularImageViewStyle);
    }

    public CircularImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs, defStyle);
    }

    /**
     * 初始化paint对象和设置所需的属性。
     *
     * @param context
     * @param attrs
     * @param defStyle
     */
    private void init(Context context, AttributeSet attrs, int defStyle) {
        // 初始化paint对象
        paint = new Paint();
        paint.setAntiAlias(true);
        paintBorder = new Paint();
        paintBorder.setAntiAlias(true);
        paintSelectorBorder = new Paint();
        paintSelectorBorder.setAntiAlias(true);

        TypedArray attributes = context.obtainStyledAttributes(attrs,
                R.styleable.CircularImageView, defStyle, 0);

        // 是否启用了边界和点击事件
        hasBorder = attributes.getBoolean(R.styleable.CircularImageView_border,
                false);
        hasSelector = attributes.getBoolean(
                R.styleable.CircularImageView_selector, false);

        // 启用设置边框属性
        if (hasBorder) {
            int defaultBorderSize = (int) (2 * context.getResources()
                    .getDisplayMetrics().density + 0.5f);
            setBorderWidth(attributes.getDimensionPixelOffset(
                    R.styleable.CircularImageView_border_width,
                    defaultBorderSize));
            setBorderColor(attributes.getColor(
                    R.styleable.CircularImageView_border_color, Color.WHITE));
        }

        // 启用设置属性
        if (hasSelector) {
            int defaultSelectorSize = (int) (2 * context.getResources()
                    .getDisplayMetrics().density + 0.5f);
            setSelectorColor(attributes.getColor(
                    R.styleable.CircularImageView_selector_color,
                    Color.TRANSPARENT));
            setSelectorStrokeWidth(attributes.getDimensionPixelOffset(
                    R.styleable.CircularImageView_selector_stroke_width,
                    defaultSelectorSize));
            setSelectorStrokeColor(attributes.getColor(
                    R.styleable.CircularImageView_selector_stroke_color,
                    Color.BLUE));
        }

        // 添加一个影子
        if (attributes.getBoolean(R.styleable.CircularImageView_shadow, false))
            addShadow();

        // 清理
        attributes.recycle();
    }

    /**
     * 设置CircularImageView边框宽度。
     *
     * @param borderWidth
     */
    public void setBorderWidth(int borderWidth) {
        this.borderWidth = borderWidth;
        this.requestLayout();
        this.invalidate();
    }

    /**
     * 设置边框颜色
     *
     * @param borderColor
     */
    public void setBorderColor(int borderColor) {
        if (paintBorder != null)
            paintBorder.setColor(borderColor);
        this.invalidate();
    }

    /**
     * 点击颜色选择器是在CircularImageView画。一定要提供一些透明度
     *
     * @param selectorColor
     */
    public void setSelectorColor(int selectorColor) {
        this.selectorFilter = new PorterDuffColorFilter(selectorColor,
                PorterDuff.Mode.SRC_ATOP);
        this.invalidate();
    }

    /**
     * 点击后边框宽度
     *
     * @param selectorStrokeWidth
     */
    public void setSelectorStrokeWidth(int selectorStrokeWidth) {
        this.selectorStrokeWidth = selectorStrokeWidth;
        this.requestLayout();
        this.invalidate();
    }

    /**
     * 点击后边框颜色
     *
     * @param borderColor
     */
    public void setSelectorStrokeColor(int selectorStrokeColor) {
        if (paintSelectorBorder != null)
            paintSelectorBorder.setColor(selectorStrokeColor);
        this.invalidate();
    }

    /**
     * 在这个CircularImageView上添加一个阴影。
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public void addShadow() {
        setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
        paintBorder.setShadowLayer(3.0f, 2.0f, 2.0f, Color.parseColor("#33000000"));
    }

    @Override
    public void onDraw(Canvas canvas) {
        if (image == null)
            return;

        if (image.getHeight() == 0 || image.getWidth() == 0)
            return;

        // 比较画布大小
        int oldCanvasSize = canvasSize;

        canvasSize = canvas.getWidth();
        if (canvas.getHeight() < canvasSize)
            canvasSize = canvas.getHeight();

        // 重新启动材质,如果必要的
        if (oldCanvasSize != canvasSize)
            refreshBitmapShader();

        // 着色器适用于paint
        paint.setShader(shader);

        int outerWidth = 0;

        int center = canvasSize / 2;

        if (hasSelector && isSelected) {
            outerWidth = selectorStrokeWidth;
            center = (canvasSize - (outerWidth * 2)) / 2;

            paint.setColorFilter(selectorFilter);
            canvas.drawCircle(center + outerWidth, center + outerWidth,
                    ((canvasSize - (outerWidth * 2)) / 2) + outerWidth - 4.0f,
                    paintSelectorBorder);
        } else if (hasBorder) {
            outerWidth = borderWidth;
            center = (canvasSize - (outerWidth * 2)) / 2;

            paint.setColorFilter(null);
            canvas.drawCircle(center + outerWidth, center + outerWidth,
                    ((canvasSize - (outerWidth * 2)) / 2) + outerWidth - 4.0f,
                    paintBorder);
        } else
            paint.setColorFilter(null);

        // 画出圆形图像本身
        canvas.drawCircle(center + outerWidth, center + outerWidth,
                ((canvasSize - (outerWidth * 2)) / 2) - 4.0f, paint);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        // 如果禁用检查可点击的状态,什么都不做
        if (!this.isClickable()) {
            this.isSelected = false;
            return super.onTouchEvent(event);
        }

        // 设置选定状态基于运动事件
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                this.isSelected = true;
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_SCROLL:
            case MotionEvent.ACTION_OUTSIDE:
            case MotionEvent.ACTION_CANCEL:
                this.isSelected = false;
                break;
        }

        // 重绘形象和返回超类型
        this.invalidate();
        return super.dispatchTouchEvent(event);
    }

    public void invalidate(Rect dirty) {
        super.invalidate(dirty);
        image = drawableToBitmap(getDrawable());
        if (shader != null || canvasSize > 0)
            refreshBitmapShader();
    }

    public void invalidate(int l, int t, int r, int b) {
        super.invalidate(l, t, r, b);
        image = drawableToBitmap(getDrawable());
        if (shader != null || canvasSize > 0)
            refreshBitmapShader();
    }

    @Override
    public void invalidate() {
        super.invalidate();
        image = drawableToBitmap(getDrawable());
        if (shader != null || canvasSize > 0)
            refreshBitmapShader();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = measureWidth(widthMeasureSpec);
        int height = measureHeight(heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    private int measureWidth(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = specSize;
        } else {
            result = canvasSize;
        }

        return result;
    }

    private int measureHeight(int measureSpecHeight) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpecHeight);
        int specSize = MeasureSpec.getSize(measureSpecHeight);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = specSize;
        } else {
            result = canvasSize;
        }

        return (result + 2);
    }

    /**
     * 转化成Bitmap
     *
     * @param drawable
     * @return
     */
    public Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable == null) {
            return null;
        } else if (drawable instanceof BitmapDrawable) { // Use the getBitmap()
            // method instead if
            // BitmapDrawable
            return ((BitmapDrawable) drawable).getBitmap();
        }

        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
                drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);

        return bitmap;
    }

    /**
     * 重新启动材质纹理用于填写在画圆。
     */
    public void refreshBitmapShader() {
        shader = new BitmapShader(Bitmap.createScaledBitmap(image, canvasSize,
                canvasSize, false), Shader.TileMode.CLAMP,
                Shader.TileMode.CLAMP);
    }

    /**
     * 返回是否能点击的状态。
     */
    public boolean isSelected() {
        return this.isSelected;
    }
}